package com.hmdp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.config.ResultCodeEnum;
import com.hmdp.config.SmsException;
import com.hmdp.dto.LoginFormDTO;
import com.hmdp.dto.Result;
import com.hmdp.dto.UserDTO;
import com.hmdp.entity.User;
import com.hmdp.mapper.UserMapper;
import com.hmdp.service.IUserService;
import com.hmdp.service.SmsService;
import com.hmdp.sms.CodeUtil;
import com.hmdp.utils.JwtUtil;
import com.hmdp.utils.RedisConstants;
import com.hmdp.utils.RegexUtils;
import com.hmdp.utils.SystemConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;


/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Autowired
    private SmsService smsService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private UserMapper userMapper;
    //获取并保存验证
    @Override
    public void getSMSCode(String phone) {
        // 1.校验手机号
        if (RegexUtils.isPhoneInvalid(phone)) {
            // 2.如果不符合，返回错误信息
            throw new SmsException(ResultCodeEnum.APP_LOGIN_PHONE_ERROR);
        }
        //生成四位验证码
        String code = CodeUtil.getRandomCode(4);
        //创建存入验证码到redis的key
        String key = RedisConstants.LOGIN_CODE_KEY + phone;
        //判断是否存在验证码
        Boolean hasKey = stringRedisTemplate.hasKey(key);
        if (hasKey) {
            //若存在，获取key的ttl
            Long ttl = stringRedisTemplate.getExpire(key, TimeUnit.SECONDS);
            //RedisConstants.LOGIN_CODE_TTL-ttl=保存时间-剩余时间=已保存时间
            //如果小于60s（我的key保存时间是180天）就相当于还未保存到60s，
            if (RedisConstants.LOGIN_CODE_TTL-ttl< 300L) {
                //验证法发送过于频繁
                throw new SmsException(ResultCodeEnum.APP_SEND_SMS_TOO_OFTEN);
            }
        }
        //不存在，则保存并发送验证码,为了节约钱，保存15552000秒=180天
        stringRedisTemplate.opsForValue().set(key, code, RedisConstants.LOGIN_CODE_TTL, TimeUnit.SECONDS);
        smsService.sendSms(phone, code);
    }

    @Override
    public Result login(LoginFormDTO loginForm, HttpSession session) {
        // 1.校验手机号
        String phone = loginForm.getPhone();
        if (RegexUtils.isPhoneInvalid(phone)) {
            // 2.如果不符合，返回错误信息throw new SmsException(ResultCodeEnum.APP_LOGIN_PHONE_ERROR);
            return Result.fail("手机号格式错误！");
        }
        // 3.校验验证码
        String key = RedisConstants.LOGIN_CODE_KEY + phone;
        String code = stringRedisTemplate.opsForValue().get(key);
        //redis验证码是否存在
        if (!StringUtils.hasLength(code)) {
            //不存在
            return Result.fail("验证码已过期！");
        }
        //验证码是否一致
        if (!loginForm.getCode().equals(code)) {
            return Result.fail("验证码错误！");
        }
        //验证码也对，查询该用户
        LambdaQueryWrapper<User> qw = new LambdaQueryWrapper<>();
        qw.eq(User::getPhone,phone);
        User user = userMapper.selectOne(qw);
        //用户存在否？
        if (user == null) {
            //注册
            user = new User();
            user.setPhone(phone);
            user.setNickName(SystemConstants.USER_NICK_NAME_PREFIX+ RandomUtil.randomString(10));
            userMapper.insert(user);
        }
        System.err.println(user);
        //7.保存用户信息到session中，正常情况
//        session.setAttribute("user",user);
        //生成jwt
        String token= JwtUtil.createToken(user.getId(), user.getNickName());
        //将user对象转为map存储
        UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
        Map<String, Object> map = BeanUtil.beanToMap(userDTO, new HashMap<>(),
                CopyOptions.create()
                        .setIgnoreNullValue(true)
                        .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
        //保存到redis中并设置过期时间
        stringRedisTemplate.opsForHash().putAll(token,map);
        stringRedisTemplate.expire(token,30,TimeUnit.MINUTES);
        System.err.println(token);
        return Result.ok(token);
    }
}
